#!/usr/bin/env python3
"""
VectorDB Microservice - A standalone LanceDB vector database service

This service provides:
- Async vector operations with connection pooling
- Multiple embedding provider support (Ollama, OpenAI, etc.)
- RESTful API endpoints
- WebSocket support for real-time operations
- RAG (Retrieval-Augmented Generation) capabilities
"""

import asyncio
import logging
import os
import signal
import sys
from contextlib import asynccontextmanager
from pathlib import Path

import uvicorn
from fastapi import FastAPI, WebSocket, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from api.routes import router as api_router
from api.websocket import websocket_endpoint, websocket_handler
from core.config import get_config, config_manager
from core.database import get_db_manager, close_db_manager
from core.embedding import close_embedding_service

# Configure logging
def setup_logging():
    """Set up logging configuration."""
    config = get_config()
    log_config = config.logging

    # Create logs directory
    log_file = Path(log_config.file)
    log_file.parent.mkdir(parents=True, exist_ok=True)

    # Configure logging
    logging.basicConfig(
        level=getattr(logging, log_config.level.upper()),
        format=log_config.format,
        handlers=[
            logging.StreamHandler() if log_config.console else logging.NullHandler(),
            logging.handlers.RotatingFileHandler(
                log_config.file,
                maxBytes=log_config.max_size,
                backupCount=log_config.backup_count
            )
        ]
    )

    return logging.getLogger(__name__)


logger = setup_logging()


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan manager."""
    logger.info("Starting VectorDB Microservice...")

    try:
        # Initialize database manager
        logger.info("Initializing database manager...")
        db_manager = await get_db_manager()
        logger.info("Database manager initialized successfully")

        # Initialize embedding service
        logger.info("Initializing embedding service...")
        from core.embedding import get_embedding_service
        embedding_service = await get_embedding_service()
        logger.info("Embedding service initialized successfully")

        # Check embedding provider health
        provider_health = await embedding_service.health_check()
        healthy_providers = [name for name, healthy in provider_health.items() if healthy]

        if healthy_providers:
            logger.info(f"Available embedding providers: {healthy_providers}")
            # Set the first healthy provider as default
            await embedding_service.set_provider(healthy_providers[0])
        else:
            logger.warning("No healthy embedding providers available")

        # Create default table if it doesn't exist
        config = get_config()
        default_table = "documents"
        tables = await db_manager.list_tables()

        if default_table not in tables:
            logger.info(f"Creating default table: {default_table}")
            await db_manager.create_table(default_table)
            logger.info(f"Default table '{default_table}' created")

        logger.info("VectorDB Microservice started successfully")
        yield

    except Exception as e:
        logger.error(f"Failed to start VectorDB Microservice: {e}")
        raise

    finally:
        logger.info("Shutting down VectorDB Microservice...")

        # Close embedding service
        try:
            await close_embedding_service()
            logger.info("Embedding service closed")
        except Exception as e:
            logger.error(f"Error closing embedding service: {e}")

        # Close database manager
        try:
            await close_db_manager()
            logger.info("Database manager closed")
        except Exception as e:
            logger.error(f"Error closing database manager: {e}")

        logger.info("VectorDB Microservice shutdown complete")


def create_app() -> FastAPI:
    """Create FastAPI application."""
    config = get_config()
    service_config = config.service

    # Create FastAPI app
    app = FastAPI(
        title=service_config.name,
        version=service_config.version,
        description="A standalone LanceDB vector database microservice with embedding support",
        lifespan=lifespan,
        docs_url="/docs" if service_config.reload else "/docs",
        redoc_url="/redoc" if service_config.reload else None,
    )

    # Add CORS middleware
    app.add_middleware(
        CORSMiddleware,
        allow_origins=config.security.cors_origins,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    # Include API routes
    app.include_router(api_router, prefix="/api/v1")

    # Add error handlers
    @app.exception_handler(HTTPException)
    async def http_exception_handler(request, exc):
        """Handle HTTP exceptions."""
        return JSONResponse(
            status_code=exc.status_code,
            content={"error": exc.detail, "timestamp": datetime.now().isoformat()}
        )

    @app.exception_handler(Exception)
    async def general_exception_handler(request, exc):
        """Handle general exceptions."""
        logger.error(f"Unhandled exception: {exc}", exc_info=True)
        return JSONResponse(
            status_code=500,
            content={"error": "Internal server error", "detail": str(exc), "timestamp": datetime.now().isoformat()}
        )

    # Root endpoint
    @app.get("/")
    async def root():
        """Root endpoint with service information."""
        return {
            "service": service_config.name,
            "version": service_config.version,
            "description": "VectorDB Microservice - LanceDB vector database with embedding support",
            "endpoints": {
                "docs": "/docs",
                "health": "/api/v1/health",
                "websocket": "/ws",
                "api": "/api/v1"
            },
            "timestamp": datetime.now().isoformat()
        }

    # WebSocket endpoint
    @app.websocket("/ws")
    async def websocket_route(websocket: WebSocket):
        """WebSocket endpoint for real-time operations."""
        await websocket_endpoint(websocket)

    # Metrics endpoint (if monitoring is enabled)
    if config.monitoring.enabled:
        @app.get(config.monitoring.metrics_endpoint)
        async def metrics():
            """Metrics endpoint for monitoring."""
            try:
                db_manager = await get_db_manager()
                stats = await db_manager.get_database_stats()
                connection_stats = websocket_handler.connection_manager.get_connection_stats()

                return {
                    "database": stats,
                    "websocket_connections": connection_stats,
                    "timestamp": datetime.now().isoformat()
                }
            except Exception as e:
                logger.error(f"Metrics endpoint error: {e}")
                return JSONResponse(
                    status_code=500,
                    content={"error": f"Failed to get metrics: {e}"}
                )

    return app


def signal_handler(signum, frame):
    """Handle system signals."""
    logger.info(f"Received signal {signum}, shutting down gracefully...")
    sys.exit(0)


def main():
    """Main entry point."""
    # Set up signal handlers
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    # Get configuration
    config = get_config()
    service_config = config.service

    # Create app
    app = create_app()

    # Run the application
    logger.info(f"Starting VectorDB Microservice on {service_config.host}:{service_config.port}")

    uvicorn.run(
        app,
        host=service_config.host,
        port=service_config.port,
        workers=service_config.workers,
        reload=service_config.reload,
        log_level=service_config.log_level.lower()
    )


if __name__ == "__main__":
    main()